package report_service

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/app/services/online_service"
	"peilian-api/utils/sdk"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

type MaskService struct{}

// 记录时间
type WsRecord struct {
	Begin float64 `json:"begin"`
	End   float64 `json:"end"`
}

type WsInfo struct {
	Bg   string  `json:"bg"`
	Ed   string  `json:"ed"`
	Wb   float64 `json:"wb"`
	We   float64 `json:"we"`
	Word string  `json:"word"`
}

/**
 * @param id  real_question 问题id
 * @param pcm pcm地址
 * @param bp []需要屏蔽的 索引id
 * @return pcmName, error
 **/
func (m *MaskService) MaskWords(ctx *gin.Context, id int) (string, error) {
	sc := variable.DB.Redis.ZRange(fmt.Sprintf(common.RedisSetMaskRIdKey, id), 0, -1)
	s, _ := sc.Result()
	// 将数据取出后，及时删除
	variable.DB.Redis.Del(fmt.Sprintf(common.RedisSetMaskRIdKey, id))
	// 1. 先查询数据是否存在
	rq, err := new(tables.RealQues).GetRealQuestionById(id)
	answerText := rq.AnswerText
	answerAudio := rq.AnswerAudio
	if err != nil {
		log.Logger.ErrorF(ctx, fmt.Sprintf("id:%d，查询错误~", id))
		return "", err
	}
	if len(answerText) == 0 {
		log.Logger.ErrorF(ctx, fmt.Sprintf("id:%d，无文本~", id))
		return "", nil
	}
	// 2. 查询是否已经处理过
	mw, err := new(tables.MaskWords).GetMaskWordsByRid(int64(rq.ID))
	if err != nil {
		return "", fmt.Errorf("get maskwords is error")
	}
	if mw.ID != 0 { // 说明被处理过
		// answerText = mw.AnswerText
		answerAudio = strings.ReplaceAll(answerAudio, "_pal.pcm", ".pcm")
	}

	// 调用接口敏感词
	var maskData = model.MaskDataResp{}
	maskDataStr := FetchDataMask(ctx, answerText)
	err = json.Unmarshal([]byte(maskDataStr), &maskData)
	if err != nil {
		return "", fmt.Errorf("mask_data error")
	}
	if len(maskData.MaskedIdxList) == 0 { // 无需处理
		return "", nil
	}
	bp := maskData.MaskedIdxList
	var wordCount = 0
	// 记录时间
	var wrs []WsRecord
	for i := 0; i < len(s); i++ {
		var winfo WsInfo
		json.Unmarshal([]byte(s[i]), &winfo)
		var b = []rune(winfo.Word)
		for j := 0; j < len(b); j++ {
			wordCount += 1
			for k := 0; k < len(bp); k++ {
				if bp[k]+1 == wordCount {
					f, _ := strconv.ParseFloat(winfo.Bg, 64)
					wr := WsRecord{}
					wrs = append(wrs, WsRecord{Begin: (winfo.Wb*10+f)/40 - 10, End: (winfo.We*10+f)/40 + 10})
					wr.Begin = winfo.Wb
				}
			}
		}
	}

	filePrefix := variable.Config.UfsInfo.UfsUrl + variable.Config.UfsInfo.BucketPrefix
	// 读取语音
	data := make([]byte, 1280)
	// audio, err := os.Open(filePrefix + rq.AnswerAudio)
	// if err != nil {
	// 	audio.Close()
	// 	return err
	// }
	// fmt.Println(filePrefix + answerAudio)
	resp, err := http.Get(filePrefix + answerAudio)
	defer resp.Body.Close()
	reader := bufio.NewReaderSize(resp.Body, 1280*32)
	if err != nil {
		return "", nil
	}

	var count = 0
	var audioBuffer = new(bytes.Buffer)
	for i, e := reader.Read(data); i > 0; i, e = reader.Read(data) {
		if e != nil {
			if e.Error() == "EOF" {
				break
			}
			return "", nil
		}
		count++
		for _, v := range wrs {
			if count >= int(v.Begin) && count <= int(v.End) {
				data = make([]byte, 1280)
				break
			}
		}
		// 将音频写入新文件
		audioBuffer.Write(data[:i])
	}

	// 将音频改写为新的 pcm 文件
	fileName := strings.Replace(answerAudio, ".pcm", "_pal.pcm", 1)
	err = sdk.IOput(audioBuffer.Bytes(), variable.Config.UfsInfo.BucketPrefix+fileName, "application/octet-stream")
	if err != nil {
		return "", fmt.Errorf("audio deal is error, id : %d, file path : %s", rq.ID, fileName)
	}
	b, _ := json.Marshal(maskData.MaskedIdxList)
	tokenList, _ := json.Marshal(maskData.MaskedTokenList)

	var mws = tables.MaskWords{
		Rid:               int64(rq.ID),
		AnswerAudioOrigin: answerAudio,
		AnswerAudioMask:   fileName,
		AnswerMaskWords:   string(tokenList),
		AnswerMaskIds:     string(b),
		AnswerText:        answerText,
		AnswerTextMask:    maskData.MaskedText,
	}
	// 做数据备份 先查询是否存在，如果存在则更新, 否则插入
	if mw.ID != 0 {
		err = new(tables.MaskWords).UpdateMaskWords(mw.ID, mws, "answer_text", "answer_audio_mask", "answer_mask_words", "answer_mask_ids", "answer_text_mask")
		if err != nil {
			return "", fmt.Errorf("mask worlds update error")
		}
	} else {
		id, err := new(tables.MaskWords).CreateMaskWords(mws)
		if err != nil || id == 0 {
			return "", fmt.Errorf("mask worlds insert error")
		}
	}

	// 更新real_question
	var updateWhere = make(map[string]interface{}, 0)
	updateWhere["answer_text"] = maskData.MaskedText
	updateWhere["answer_audio"] = fileName

	// 转mp3
	mp3Name, err := online_service.OptionFfmpegToMp3(filePrefix+fileName, int(rq.ID))
	if err != nil {
		log.Logger.InfoMsgF(ctx, fmt.Sprintf("mp3 upload is error, id: %d, mp3 path: %s", rq.ID, mp3Name))
	}
	dataTime := strings.Split(answerAudio, "/")
	if len(dataTime) < 3 {
		return "", fmt.Errorf("audio path error")
	}
	mp3Path := fmt.Sprintf(filePrefix+"/static/mp3/%s/%s", dataTime[len(dataTime)-2 : len(dataTime)-1][0], mp3Name)
	updateWhere["audio"] = mp3Path
	d := variable.DB.MySQL.Model(&tables.RealQues{}).Where("id = ?", rq.ID).Updates(updateWhere).Limit(1)
	if d.Error != nil {
		return "", d.Error
	}
	return fileName, nil
}
